#include "Tree.h"
#include "BasicTypes.h"
extern "C" {
#include <epan/value_string.h>
}

using namespace std;

void CopyChild(proto_node * child, gpointer _this )
{
	Tree::Node * This = (Tree::Node *)_this;
	Tree::Node * tnChild = new Tree::Node(child, This->m_level + 1);
	if ( tnChild->HasMeaning() )
		This->m_children.push_back(tnChild);
	else
		delete tnChild;
}

void AddRoot(proto_node * child, gpointer _this )
{
	Tree * This = (Tree *)_this;
	Tree::Node * tnChild = new Tree::Node(child, 1);
	if ( tnChild->HasMeaning() )
		This->m_roots.push_back(tnChild);
	else
		delete tnChild;
}

Tree::Node::Node(proto_node * epan_node, int level)
{
	char label[256];
	if ( epan_node->finfo->rep != NULL )
		m_caption = string(epan_node->finfo->rep->representation);
	else
	{
		proto_item_fill_label(epan_node->finfo, label);
		m_caption = string(label);
	}
		
	m_offset = epan_node->finfo->start;
	m_size = epan_node->finfo->length;
	m_level = level;
    m_isHidden = epan_node->finfo->flags & FI_HIDDEN;
	proto_tree_children_foreach(epan_node, CopyChild, this);
}
Tree::Node::~Node()
{
	for (size_t i = 0; i < m_children.size(); i++)
	{
		delete m_children[i];
	}
	m_children.clear();
}

bool Tree::Node::HasMeaning() const
{
    return (!m_isHidden) && 
           ((m_caption.length() > 0) || (m_children.size() > 0));
}

std::string my_itoa(unsigned value)
{
	const size_t bufsize = 12;
	char buffer[bufsize];
	if (_itoa_s<bufsize>((unsigned int)value, buffer, 10))
		throw "Cannot convert integer to string";
	
	std::string result(buffer);

	return result;
}


string Tree::Node::GetXMLData()
{
	std::string data;
	data.append(m_level, ' ');
	data += "<node offset=\"";
	data += my_itoa((unsigned int)m_offset);
	data += "\" size=\"";
	data += my_itoa((unsigned int)m_size);
	data += "\">\n";
	data.append(m_level + 1, ' ');
	data += "<decoded-data>";
	data += XMLString(m_caption);
	data += "</decoded-data>\n";
	for (size_t i = 0; i < m_children.size(); i++)
	{
		data += m_children[i]->GetXMLData();
	}
	data.append(m_level, ' ');
	data += "</node>\n";
	return data;
}

Tree::Tree(proto_tree & epan_tree)
{
	proto_tree_children_foreach(&epan_tree, AddRoot, this);
}

Tree::~Tree()
{
	vector< Tree::Node * >::iterator it = m_roots.begin();
	while ( it != m_roots.end() )
	{
		delete *it;
		it++;
	}
}

string Tree::GetTreeData(TreeFormat format)
{
	string result = "";
	vector< Tree::Node * >::iterator it;
	it = m_roots.begin();
	switch (format)
	{
	case TF_XML:
		result += "<tree version=\"0\">\n";
		while ( it != m_roots.end() )
		{
			result += (*it)->GetXMLData();
			it++;
		}
		result += "</tree>";
		break;
	default:
		result = "";
	}
	return result;
}

string XMLString(string source)
{
	string result;
	size_t index = 0;
	size_t length = source.length(); 
	while (index < length)
	{
		switch (source[index])
		{
		case '&':
			result += "&amp;";
			index++;
			break;
		case '<':
			result += "&lt;";
			index++;
			break;
		default:
			size_t pos = source.find_first_of("&<", index);
			size_t len = (pos == string::npos ? length : pos) - index;
			result.append(source, index, len);
			index += len;
		}
	}
	return result;
}